using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Kontakter
{
    public partial class MainForm : Form
    {
        #region Declarations

        private Options options = null;

        private Logic logic = null;

        private Thread changeConnectionStatusThread;

        private Thread blinkThread = null;

        #region Delegates

        private delegate void ShowConnectionStatusDelegate(bool connected);

        private delegate void UpdateFriendsDelegate(UpdateType type);

        private delegate void ClearFriendsNodeDelegate();

        private delegate void UpdateNewMessagesCountDelegate(int newMessages);

        #endregion

        #endregion

        #region c'tor

        public MainForm()
        {
            InitializeComponent();
            CustomInitialize();
        }

        #endregion

        #region Custom initialization

        private void CustomInitialize()
        {
            InitializeRootNode();

            treeView.TreeViewNodeSorter = new NodeSorter();
            treeView.NodeMouseDoubleClick +=
                new TreeNodeMouseClickEventHandler(FriendNodeMouseDoubleClick);
        }

        private void InitializeRootNode()
        {
            TreeNode friendsNode = new TreeNode();

            friendsNode.Name = "FriendsNode";
            friendsNode.Text = "Friends";
            friendsNode.NodeFont =
                new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            friendsNode.Expand();

            treeView.Nodes.Add(friendsNode);
        }

        #endregion

        #region Overrides

        protected override void OnCreateControl()
        {
            options = Options.CreateInstance();
            if (!options.Load())
                ShowOptionsForm();

            int x = options.MainWindowState.LocX;
            int y = options.MainWindowState.LocY;
            int size_x = options.MainWindowState.SizeX;
            int size_y = options.MainWindowState.SizeY;

            this.SetBounds(x, y, size_x, size_y);
            this.WindowState = FormWindowState.Normal;

            logic = Logic.CreateInstance(options);

            logic.ConnectionStatusChanged += new Logic.ConnectionStatusEventHandler(ConnectionStatusChanged);
            logic.FriendsUpdated += new Logic.FriendsUpdatedEventHandler(FriendsUpdated);
            logic.NewMessagesCountUpdated += new Logic.NewMessagesCountUpdatedEventHandler(NewMessagesCountUpdated);

 	        base.OnCreateControl();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            options.MainWindowState.LocX = this.Location.X;
            options.MainWindowState.LocY = this.Location.Y;
            options.MainWindowState.SizeX = this.Size.Width;
            options.MainWindowState.SizeY = this.Size.Height;

            options.Save();
            Logic.ReleaseInstance();

            StopBlinking();

            base.OnClosing(e);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Visible = false;
                notifyIcon.Visible = true;
            }
        }

        #endregion

        #region Menu event handlers

        private void OptionsMenuItemClick(object sender, EventArgs e)
        {
            ShowOptionsForm();
        }

        private void AboutMenuItemClick(object sender, EventArgs e)
        {
        }

        private void QuitMenuItemClick(object sender, EventArgs e)
        {
            this.Close();
        }

        private void ConnectMenuItemClick(object sender, EventArgs e)
        {
            changeConnectionStatusThread = new Thread(new ParameterizedThreadStart(ChangeConnectionStatus));
            changeConnectionStatusThread.Start(true);
        }

        private void DisconnectMenuItemClick(object sender, EventArgs e)
        {
            changeConnectionStatusThread = new Thread(new ParameterizedThreadStart(ChangeConnectionStatus));
            changeConnectionStatusThread.Start(false);
        }

        #endregion

        #region Other controls event handlers

        private void FriendNodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            TreeNode node = e.Node;
            if (node.Level == 1)
            {
                PrivateForm f = new PrivateForm(logic, (int)e.Node.Tag);
                f.Show();
            }
        }

        private void TrayIconMouseClick(object sender, MouseEventArgs e)
        {
            this.Visible = true;
            this.WindowState = FormWindowState.Normal;
            notifyIcon.Visible = false;
        }

        private void ConnectionStatusChanged(object sender, bool connected)
        {
            ShowConnectionStatus(connected);
        }

        private void FriendsUpdated(object sender, int friendId, UpdateType type)
        {
            UpdateFriends(type);
        }

        private void NewMessagesCountUpdated(object sender, int newMessages)
        {
            UpdateNewMessagesCount(newMessages);
        }

        #endregion

        #region Methods

        private void ChangeConnectionStatus(object obj)
        {
            bool connect = (bool)obj;
            if (connect)
            {
                string errMessage;
                if (!logic.Connect(out errMessage))
                {
                    if (errMessage == "")
                        errMessage = "Could not connect to host: http://vkontakte.ru.\n" +
                                     "Please, try to check your internet connection.";
                    MessageBox.Show(errMessage, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    UpdateFriends(UpdateType.All);
                }
            }
            else
            {
                ClearFriendsNode();

                logic.Disconnect();
                logic.FastUpdate();
            }
        }

        private void ShowOptionsForm()
        {
            OptionsForm form = new OptionsForm(options);

            form.ShowDialog();
        }

        private void ShowConnectionStatus(bool connected)
        {
            if (this.ConnectionStatusLabel.InvokeRequired)
            {
                ShowConnectionStatusDelegate d = new ShowConnectionStatusDelegate(ShowConnectionStatus);
                this.Invoke(d, new object[] { connected });
            }
            else
                ConnectionStatusLabel.Text = connected ? "Connected" : "Disconnected";
        }

        private void ClearFriendsNode()
        {
            if (this.treeView.InvokeRequired)
            {
                ClearFriendsNodeDelegate d = new ClearFriendsNodeDelegate(ClearFriendsNode);
                this.Invoke(d, new object[] { });
            }
            else
            {
                treeView.Nodes["FriendsNode"].Nodes.Clear();
            }
        }

        private void UpdateFriends(UpdateType type)
        {
            if (this.treeView.InvokeRequired)
            {
                UpdateFriendsDelegate d = new UpdateFriendsDelegate(UpdateFriends);
                this.Invoke(d, new object[] { type });
            }
            else
            {
                foreach (KeyValuePair<int, Friend> key in logic.Friends)
                {
                    if (!treeView.Nodes["FriendsNode"].Nodes.ContainsKey(key.Key.ToString()))
                    {
                        TreeNode friendNode = new TreeNode();

                        friendNode.Name = key.Key.ToString();

                        if (key.Value.NewMessages != 0)
                            friendNode.Text = "(" + key.Value.NewMessages.ToString() + ") " + key.Value.Name;
                        else
                            friendNode.Text = key.Value.Name;

                        friendNode.NodeFont = new Font("Microsoft Sans Serif", 8, 
                            key.Value.Status ? FontStyle.Bold : FontStyle.Regular);

                        friendNode.Tag = key.Key;

                        treeView.Nodes["FriendsNode"].Nodes.Add(friendNode);
                    }
                    else
                    {
                        if (type == UpdateType.Status || type == UpdateType.All)
                        {
                            if (treeView.Nodes["FriendsNode"].Nodes[key.Key.ToString()].NodeFont.Bold != key.Value.Status)
                            {
                                treeView.Nodes["FriendsNode"].Nodes[key.Key.ToString()].NodeFont =
                                    new Font("Microsoft Sans Serif", 8,
                                    key.Value.Status ? FontStyle.Bold : FontStyle.Regular);
                            }
                        }

                        if (type == UpdateType.NewMessagesCount || type == UpdateType.All)
                        {
                            // todo: update must be performed only when NewMessages was changed

                            if (key.Value.NewMessages != 0)
                            {
                                treeView.Nodes["FriendsNode"].Nodes[key.Key.ToString()].Text =
                                    "(" + key.Value.NewMessages.ToString() + ") " + key.Value.Name;
                            }
                            else
                                treeView.Nodes["FriendsNode"].Nodes[key.Key.ToString()].Text = key.Value.Name;
                        }
                    }
                }
                //todo: bad, causes full repaint
                treeView.Sort();
            }
        }

        private void UpdateNewMessagesCount(int newMessages)
        {
            if (this.treeView.InvokeRequired)
            {
                UpdateNewMessagesCountDelegate d = new UpdateNewMessagesCountDelegate(UpdateNewMessagesCount);
                this.Invoke(d, new object[] {newMessages });
            }
            else
            {
                if (newMessages != 0)
                {
                    treeView.Nodes["FriendsNode"].Text = "Friends (" + newMessages.ToString() + ")";
                    StartBlinking();
                }
                else
                {
                    treeView.Nodes["FriendsNode"].Text = "Friends";
                    StopBlinking();
                }
            }
        }

        private void StartBlinking()
        {
            if (blinkThread == null)
            {
                blinkThread = new Thread(new ThreadStart(Blink));
                blinkThread.Start();
            }
        }

        private void StopBlinking()
        {
            if (blinkThread != null)
            {
                blinkThread.Abort();
                blinkThread = null;
                notifyIcon.Icon = Kontakter.Properties.Resources.Kontacter;
            }
        }

        private void Blink()
        {
            while (true)
            {
                notifyIcon.Icon = Kontakter.Properties.Resources.KontacterNewMess1;
                Thread.Sleep(1000);
                notifyIcon.Icon = Kontakter.Properties.Resources.KontacterNewMess2;
                Thread.Sleep(1000);
            }
        }

        #endregion

        #region Properties

        public Logic Logic
        {
            get
            {
                return logic;
            }
        }

        #endregion
    }
}
